/*
 * 代号：凤凰
 * http://www.jphenix.org
 * 2014-06-13
 * V4.0
 */
package	com.jphenix.webserver.servlet.jsp;

import com.jphenix.share.tools.JavacTool;
import com.jphenix.standard.docs.ClassInfo;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLDecoder;
import java.util.*;

/**
 * JSP类构建器
 * 
 * 2019-09-17 整理了代码格式
 * 
 * @author 刘虻
 * 2009-11-18下午02:23:08
 */
@ClassInfo({"2019-09-17 10:42","JSP类构建器"})
public class JSPCompiler {

    /**
	 * 构建起版本
	 */
	public static final int	COMPILER_VERSION_NR = 5;

	/**
	 * 分析过程状态
	 */
	private static final int	
						PARSE_NONE = 0,
						PARSE_HTML = 1,
						PARSE_DECLARATION = 2,
						PARSE_SCRIPTLET = 3,
						PARSE_EXPRESSION = 4;

	/**
	 * 段分隔符
	 */
	private static final String lineSeparator = System.getProperty("line.separator");

	/**
	 * 父Servlet
	 */
	private final JSPServlet jspServlet;
	private File  jspFile;          //JSP文件对象

	private final File   javaFile;  //JSP生成的java源文件
	private final String className; //类名
	
	private final HttpServletRequest servletRequest; //页面反馈

	private String  src;                           //JSP文件内容
	private int     srcPos;
	private int     lineNr;
	private int     parseState       = PARSE_NONE; //解析当前状态
	private boolean justWroteNewline = false;

	private final   Vector<Object> dependencies = new Vector<Object>();
	private boolean createSession               = false;
	private String  content_typeDirective       = null;
	
	private StringBuffer
			extendsDirective    = new StringBuffer(),
			implementsDirective = new StringBuffer(),
			importDirective     = new StringBuffer(),
			methodDirective     = new StringBuffer(),
			declarationsCode    = new StringBuffer(),
			beanCode            = new StringBuffer(),
			scriptletsCode      = new StringBuffer(),
			functionCode        = new StringBuffer();

	private String
			 pageEncoding 		//JSP编码
			,contentEncoding	//HTML内容编码
				= null;

	/**
	 * 构造函数
	 * 2009-11-18下午02:30:56
	 */
	public JSPCompiler(
			JSPServlet jspServlet
			, File jspFile
			, String className
			, HttpServletRequest servletRequest) {
		this.jspServlet     = jspServlet;
		this.jspFile        = jspFile;
		this.javaFile       = getFileForClass(jspServlet.repository, className, ".java");
		this.className      = className;
		this.servletRequest = servletRequest;
	}


	/**
	 * 执行编译
	 * @author 刘虻
	 * 2009-11-18下午02:35:40
	 * @throws JSPException 编译发生异常
	 */
	public void compile() throws JSPException {
		parseJspFile();
		generateJavaFile();
		compileJavaFile();
	}

	/**
	 * 解析JSP文件
	 * @author 刘虻
	 * 2009-11-18下午02:35:53
	 * @throws JSPException 执行发生异常
	 */
	protected void parseJspFile() throws JSPException {
		parseOneJspFile();
		changeParseState(PARSE_NONE);
		if(content_typeDirective==null) {
			content_typeDirective = jspServlet.defaultContentType;
		}
		if(extendsDirective.length()==0) {
			extendsDirective.append("javax.servlet.http.HttpServlet");
		}
		if(methodDirective.length()==0) {
			methodDirective.append("service");
		}
		
		/*
		 * 获取内容编码
		 */
		String cType = content_typeDirective.toLowerCase();
		//截取点
		int point = cType.indexOf("charset");
		if(point>-1) {
			cType = cType.substring(point+7);
			point = 0;
			while(cType.length()>point) {
				char one = cType.charAt(point);
				if(one==' ' || one=='	' || one=='\'' || one=='\n' || one=='\r' || one=='\"' || one=='=') {
					point++;
					continue;
				}
				break;
			}
			String enc = null; //编码格式
			if(point<cType.length()) {
				enc = cType.substring(point);
				point = 0;
				while(enc.length()>point) {
					char one = enc.charAt(point);
					if(one==' ' || one=='	' || one=='\'' || one=='\n' || one=='\r' || one=='\"' || one=='=') {
						break;
					}
					point++;
				}
				if(enc.length()>point) {
					enc = enc.substring(0,point);
				}
			}
			if(contentEncoding==null) {
				if(enc!=null && enc.length()>0) {
					contentEncoding = enc;
					
					extendsDirective = new StringBuffer();
					implementsDirective = new StringBuffer();
					importDirective = new StringBuffer();
					methodDirective = new StringBuffer();
					declarationsCode = new StringBuffer();
					beanCode = new StringBuffer();
					scriptletsCode = new StringBuffer();
					functionCode = new StringBuffer();
					
					parseJspFile();
				}else {
					contentEncoding = "";
				}
			}
		}
	}

	/**
	 * 解析JSP文件
	 * @author 刘虻
	 * 2009-11-18下午02:36:22
	 * @throws JSPException 执行发生异常
	 */
	protected void parseOneJspFile() throws JSPException {
		
		/*
		 * 初始化一些信息
		 */
		importDirective
			.append("import javax.servlet.http.HttpServletRequest;")
			.append(lineSeparator)
			.append("import javax.servlet.http.HttpServletResponse;")
			.append(lineSeparator);

		ByteArrayOutputStream bos; //文件内容缓存
		dependencies.addElement(jspFile);
		dependencies.addElement(new Long(jspFile.lastModified()));
		FileInputStream fis = null;
		byte[] buffer = new byte[10240];
		try {
			fis = new FileInputStream(jspFile);
			try {
				bos = new ByteArrayOutputStream();
				int bytesRead = -1;
				while((bytesRead=fis.read(buffer))!=-1) {
					bos.write(buffer,0,bytesRead);
				}
				if(contentEncoding!=null && contentEncoding.length()>0) {
					src = bos.toString(contentEncoding);
				}else {
					src = bos.toString();
				}
				bos = null;
			} finally {
				try {
					fis.close();
				}catch(Exception e) {}
			}
		} catch(FileNotFoundException fnfexc) {
			throw new JSPException(HttpServletResponse.SC_NOT_FOUND, "File " + jspFile + " could not be found");
		} catch(IOException ioexc) {
			throw new JSPException(ioexc.toString());
		}
		/*
		 * 解析JSP源代码
		 */
		lineNr = 1;
		srcPos = 0;
		try {
			while(true) {
				char oneChar = src.charAt(srcPos); //字符元素
				// check for possible state change
				if(oneChar=='<') {
					if(parseState==PARSE_NONE || parseState==PARSE_HTML) {
						if(parseInNoneOrHtmlState()) {
							continue;
						}
					} else if(parseState==PARSE_DECLARATION) {
						if(parseInDeclarationState()) {
							continue;
						}
					}
				} else if(oneChar=='%' &&
					(parseState==PARSE_EXPRESSION || parseState==PARSE_SCRIPTLET) &&
					(srcPos < src.length()-1 && src.charAt(srcPos+1)=='>')){
					// end of expression or scriptlet
					changeParseState(PARSE_NONE);
					srcPos += 2;
					continue;
				}

				// output character
				switch(parseState) {
					case PARSE_NONE:
						changeParseState(PARSE_HTML);
					case PARSE_HTML:
						if(justWroteNewline && oneChar!='\n') {
							justWroteNewline = false;
							scriptletsCode.append("\" +").append(lineSeparator).append("\t\t\t\"");
						}
						switch(oneChar) {
						case '\b':
							scriptletsCode.append("\\b");
							break;
						case '\t':
							scriptletsCode.append("\\t");
							break;
						case '\n':
							scriptletsCode.append("\\n");
							justWroteNewline = true;
							lineNr++;
							break;
						case '\r':
							scriptletsCode.append("\\r");
							justWroteNewline = true;
							lineNr++;
							break;
						case '\f':
							scriptletsCode.append("\\f");
							break;
						case '\'':
							scriptletsCode.append("\\\'");
							break;
						case '\"':
							scriptletsCode.append("\\\"");
							break;
						case '\\':
							scriptletsCode.append("\\\\");
							break;
						default:
							/*
							 * 在AIX下使用这些代码导致中文显示乱码
							 */
//							if(oneChar > 0xFF) {
//								lineStr = "00" + Integer.toHexString(oneChar);
//								scriptletsCode.append("\\u").append(lineStr.substring(lineStr.length() - 4));
//							} else if(oneChar < ' ' || oneChar >= 0x7F) {
//								lineStr = "00" + Integer.toOctalString(oneChar);
//								scriptletsCode.append('\\').append(lineStr.substring(lineStr.length() - 3));
//							} else {
//								scriptletsCode.append(oneChar);
//							}
							scriptletsCode.append(oneChar);
							break;
						}
						break;
					case PARSE_DECLARATION:
						if(oneChar=='\n') {
							declarationsCode.append(lineSeparator);
							lineNr++;
						} else {
							declarationsCode.append(oneChar);
						}
						break;
					default:
						if(oneChar=='\n') {
							scriptletsCode.append(lineSeparator);
							lineNr++;
						} else {
							scriptletsCode.append(oneChar);
						}
						break;
				}
				srcPos++;
			}
		} catch(StringIndexOutOfBoundsException sioobexc) {
			// instead of checking for the end of the string ourselves
			// we let java.lang.String find it. This makes the code
			// simpeler and more efficient.
		}
	}

	
	/**
	 * 解析非JSP内容
	 * @author 刘虻
	 * 2009-11-18下午02:53:22
	 * @return 是否解析成功
	 * @throws StringIndexOutOfBoundsException 解析发生异常
	 * @throws JSPException 执行发生异常
	 */
	protected boolean parseInNoneOrHtmlState() throws StringIndexOutOfBoundsException, JSPException {
		String[]	keyAndValue;
		char		d;
		if(srcPos < src.length()-3 && src.charAt(srcPos+1)=='%') {
			// directive or start of expression or scriptlet
			d = src.charAt(srcPos+2);
			if(d=='=') {
				// start of expression
				changeParseState(PARSE_EXPRESSION);
				setSrcPos(srcPos+3);
				return true;
			} else if(d=='@') {
				// directive
				parseDirective();
				return true;
			} else if(d=='!') {
				parseFunction();
				return true;
			} else {
				// start of scriplet
				changeParseState(PARSE_SCRIPTLET);
				setSrcPos(srcPos+2);
				return true;
			}
		} else if(srcPos < src.length()-20 &&
					"!--#INCLUDE".equalsIgnoreCase(src.substring(srcPos+1, srcPos+12)) &&
					Character.isWhitespace(src.charAt(srcPos+12))){
			parseSSI();
			return true;
		} else if(srcPos < src.length()-20 &&
					"SCRIPT".equalsIgnoreCase(src.substring(srcPos+1, srcPos+7)) &&
					Character.isWhitespace(src.charAt(srcPos+7))) {
			// possible start of declaration
			boolean	runatServer = false;
			int		prevSrcPos = srcPos,
					prevLineNr = lineNr;

			srcPos += 7;
			skipWhitespace();
			while(true) {
				// check for end of tag
				if(src.charAt(srcPos)=='>') {
					if(runatServer) {
						// start of declaration
						changeParseState(PARSE_DECLARATION);
						srcPos++;
						return true;
					} else {
						srcPos = prevSrcPos;
						lineNr = prevLineNr;
						return false;
					}
				}
				keyAndValue = parseKeyAndValue();
				if("RUNAT".equalsIgnoreCase(keyAndValue[0]) && "SERVER".equalsIgnoreCase(keyAndValue[1])) {
					runatServer = true;
				}
			}
		} else if(srcPos < src.length()-10 &&
					"BEAN".equalsIgnoreCase(src.substring(srcPos+1, srcPos+5)) &&
					Character.isWhitespace(src.charAt(srcPos+5))){
			// bean
			parseBean();
			return true;
		}

		return false;
	}

	/**
	 * 解析声明部分
	 * @author 刘虻
	 * 2009-11-18下午02:56:35
	 * @return 是否解析成功
	 * @throws StringIndexOutOfBoundsException 解析发生异常
	 * @throws JSPException 执行发生异常
	 */
	protected boolean parseInDeclarationState() throws StringIndexOutOfBoundsException, JSPException {
		if(srcPos < src.length()-8 &&
				"/SCRIPT".equalsIgnoreCase(src.substring(srcPos+1, srcPos+8)) &&
				(Character.isWhitespace(src.charAt(srcPos+8)) || src.charAt(srcPos+8)=='>')){
			// end of declaration
			changeParseState(PARSE_NONE);
			setSrcPos(src.indexOf('>', srcPos));
			srcPos++;
			return true;
		}
		return false;
	}


	
	/**
	 * 解析方法
	 * @author 刘虻
	 * 2009-12-14上午11:25:39
	 * @throws StringIndexOutOfBoundsException 解析异常
	 * @throws JSPException 执行发生异常
	 */
	protected void parseFunction() throws StringIndexOutOfBoundsException, JSPException {
		char			c;
		srcPos += 3;
		skipWhitespace();
		while(true) {
			// check for end of directive
			c = src.charAt(srcPos);
			if(c=='%') {
				if(src.charAt(srcPos+1)=='>') {
					srcPos += 2;
				} else {
					srcPos++;
					functionCode.append(c);
					continue;
				}
				functionCode.append("\n\n");
				return;
			}
			functionCode.append(c);
			srcPos++;
		}
	}
	
	
	/**
	 * 解析声明内容
	 * @author 刘虻
	 * 2009-11-18下午02:57:17
	 * @throws StringIndexOutOfBoundsException 解析发生异常
	 * @throws JSPException 执行发生异常
	 */
	protected void parseDirective() throws StringIndexOutOfBoundsException, JSPException {
		String[]		keyAndValue;
		StringTokenizer	toker;
		char			c;
		srcPos += 3;
		skipWhitespace();
		while(true) {
			// check for end of directive
			c = src.charAt(srcPos);
			if(c=='%') {
				if(src.charAt(srcPos+1)=='>') {
					srcPos += 2;
				} else {
					srcPos++;
				}
				return;
			} else if(c=='>') {
				srcPos++;
				return;
			}
			keyAndValue = parseKeyAndValue();
			if("contenttype".equalsIgnoreCase(keyAndValue[0])) {
				// content_type
				if(content_typeDirective==null) {
					content_typeDirective = keyAndValue[1];
				}
			} else if("extends".equalsIgnoreCase(keyAndValue[0])) {
				// extends
				if(extendsDirective.length()==0) {
					extendsDirective.append(lineSeparator);
					recordFileAndLineNr(extendsDirective);
					extendsDirective.append(keyAndValue[1]);
				}
			} else if("implements".equalsIgnoreCase(keyAndValue[0])) {
				// implements
				toker = new StringTokenizer(keyAndValue[1], " ,");
				while(toker.hasMoreTokens()) {
					if(implementsDirective.length()==0) {
						implementsDirective.append(" implements").append(lineSeparator);
					} else {
						implementsDirective.append(",").append(lineSeparator);
					}
					recordFileAndLineNr(implementsDirective);
					implementsDirective.append(toker.nextToken());
				}
			} else if("import".equalsIgnoreCase(keyAndValue[0])) {
				// import
				toker = new StringTokenizer(keyAndValue[1], " ,");
				while(toker.hasMoreTokens()) {
					recordFileAndLineNr(importDirective);
					importDirective.append("import ").append(toker.nextToken()).append(';').append(lineSeparator);
				}
			} else if("include".equalsIgnoreCase(keyAndValue[0]) || "file".equalsIgnoreCase(keyAndValue[0])) {
				// include
				parseInclude(keyAndValue[1], false);
			} else if("language".equalsIgnoreCase(keyAndValue[0])) {
				// language
				if(!"java".equalsIgnoreCase(keyAndValue[1])) {
					throw new JSPException("<B>" + jspFile.getPath() + ":" + lineNr + "</B>: Unknown jsp language " + keyAndValue[1]);
				}
			} else if("method".equalsIgnoreCase(keyAndValue[0])) {
				// method
				if(methodDirective.length()==0) {
					methodDirective.append(lineSeparator);
					recordFileAndLineNr(methodDirective);
					methodDirective.append(keyAndValue[1]);
				}
			} else if("vinclude".equalsIgnoreCase(keyAndValue[0])) {
				// vinclude
				parseInclude(keyAndValue[1], true);
			} else if("pageencoding".equalsIgnoreCase(keyAndValue[0])) {
				pageEncoding = keyAndValue[1];
			} else {
				throw new JSPException("<B>" + jspFile.getPath() + ":" + lineNr + "</B>: Unknown jsp directive '<I>" + keyAndValue[0] + "</I>'");
			}
		}
	}

	/**
	 * 解析虚拟路径
	 * @author 刘虻
	 * 2009-11-18下午02:58:08
	 * @throws StringIndexOutOfBoundsException 解析发生异常
	 * @throws JSPException 执行发生异常
	 */
	protected void parseSSI() throws StringIndexOutOfBoundsException, JSPException {
		String[]		keyAndValue;
		srcPos += 12;
		skipWhitespace();
		keyAndValue = parseKeyAndValue();
		if("FILE".equalsIgnoreCase(keyAndValue[0])) {
			parseInclude(keyAndValue[1], false);
		} else if("VIRTUAL".equalsIgnoreCase(keyAndValue[0])) {
			parseInclude(keyAndValue[1], true);
		} else {
			throw new JSPException("<B>" + jspFile.getPath() + ":" + lineNr + "</B>: Unknown #INCLUDE parameter " + keyAndValue[0]);
		}
		setSrcPos(src.indexOf('>', srcPos));
		srcPos++;
	}

	/**
	 * 解析包含文件
	 * @author 刘虻
	 * 2009-11-18下午02:58:41
	 * @param value
	 * @param virtual
	 * @throws StringIndexOutOfBoundsException
	 * @throws JSPException
	 * @deprecated
	 */
    protected void parseInclude(String value, boolean virtual) throws StringIndexOutOfBoundsException, JSPException {
		String s;
		File prevJspFile = jspFile;
		String prevSrc = src;
		int prevSrcPos = srcPos;
		int prevLineNr = lineNr;
		try {
			if(virtual) {
				s = servletRequest.getRealPath(value);
				if(s==null) {
                    throw new JSPException("<B>" + jspFile.getPath() + ":" + lineNr + "</B>: Virtual file " + value + " could not be mapped to a real file");
                }
				jspFile = new File(s);
			} else {
				jspFile = new File(jspFile.getParent(), value);
			}
			try {
				jspFile = new File(jspFile.getCanonicalPath());
			} catch(IOException ioexc) {
				jspFile = new File(jspFile.getAbsolutePath());
			}
			parseOneJspFile();
		} finally {
			jspFile = prevJspFile;
			src = prevSrc;
			srcPos = prevSrcPos;
			lineNr = prevLineNr;
		}
	}

	/**
	 * 解析引用类
	 * @author 刘虻
	 * 2009-11-18下午02:59:39
	 * @throws StringIndexOutOfBoundsException 解析发生异常
	 * @throws JSPException 执行发生异常
	 */
	protected void parseBean() throws StringIndexOutOfBoundsException, JSPException {
		Properties		beanAttributes;
		Hashtable<String,String>		beanDefaultProperties;
		Enumeration<String>		e;
		String[]		keyAndValue;
		String			k, v, name, varName, type, introspect,
						create, scope, beanName, getFromScope;
		int				startLineNr, endLineNr;
		startLineNr = lineNr;
		srcPos += 5;
		skipWhitespace();
		// gather <BEAN> tag parameters
		beanAttributes = new Properties();
		while(true) {
			// check for end of tag
			if(src.charAt(srcPos)=='>') {
				break;
			}
			keyAndValue = parseKeyAndValue();
			beanAttributes.put(keyAndValue[0].toLowerCase(), keyAndValue[1]);
		}
		// gather <PARAM> tags
		beanDefaultProperties = new Hashtable<String, String>();
		while(true) {
			setSrcPos(src.indexOf('<', srcPos));
			if("/BEAN".equalsIgnoreCase(src.substring(srcPos+1, srcPos+6)) &&
				(Character.isWhitespace(src.charAt(srcPos+6)) || src.charAt(srcPos+6)=='>')) {
				// </BEAN> tag
				setSrcPos(src.indexOf('>', srcPos));
				srcPos++;
				break;
			} else if("PARAM".equalsIgnoreCase(src.substring(srcPos+1, srcPos+6)) &&
				Character.isWhitespace(src.charAt(srcPos+6))) {
				// <PARAM> tag
				srcPos += 6;
				skipWhitespace();
				while(true) {
					// check for end of tag
					if(src.charAt(srcPos)=='>') {
						break;
					}
					keyAndValue = parseKeyAndValue();
					beanDefaultProperties.put(keyAndValue[0], keyAndValue[1]);
				}
			} else {
				srcPos++;
			}
		}

		// check bean attributes
		name = beanAttributes.getProperty("name");
		if(name==null) {
			throw new JSPException("<B>" + jspFile.getPath() + ":" + lineNr + "</B>: &lt;BEAN&gt; tag does not have required name attribute");
		}
		varName = beanAttributes.getProperty("varname", name);
		type = beanAttributes.getProperty("type", "Object");
		introspect = beanAttributes.getProperty("introspect", "yes");
		create = beanAttributes.getProperty("create", "yes");
		scope = beanAttributes.getProperty("scope", "request");
		beanName = beanAttributes.getProperty("beanname", type);
		if("request".equals(scope)) {
			getFromScope = "request.getAttribute(\"";
		} else if("session".equals(scope)) {
			createSession = true;
			getFromScope = "__session.getValue(\"";
		} else {
			throw new JSPException("<B>" + jspFile.getPath() + ":" + lineNr + "</B>: &lt;BEAN&gt; tag has invalid scope attribute " + scope);
		}

		// generate bean code
		endLineNr = lineNr;
		try {
			// put back line number for start of <BEAN> tag
			lineNr = startLineNr;
			if(beanCode.length()==0) {
				beanCode.append("\t\tjava.beans.PropertyDescriptor[] __propertyDescriptors;").append(lineSeparator);
			}
			// bean retrieval
			recordFileAndLineNr(beanCode);
			beanCode.append("\t\t").append(type).append(' ').append(varName)
					.append(" = null;").append(lineSeparator);
			recordFileAndLineNr(beanCode);
			beanCode.append("\t\t").append("if(").append(getFromScope).append(javaStringEncode(name))
					.append("\") instanceof ").append(type).append(") {").append(lineSeparator);
			recordFileAndLineNr(beanCode);
			beanCode.append("\t\t\t").append(varName).append(" = (").append(type).append(") ")
					.append(getFromScope).append(javaStringEncode(name)).append("\");").append(lineSeparator);
			beanCode.append("\t\t} else {").append(lineSeparator);
			if("yes".equalsIgnoreCase(create)) {
				// bean creation
				beanCode.append("\t\t\ttry {").append(lineSeparator);
				recordFileAndLineNr(beanCode);
				beanCode.append("\t\t\t\t").append(varName).append(" = (").append(type)
						.append(") ").append("java.beans.Beans.instantiate(this.getClass().getClassLoader(), \"")
						.append(beanName).append("\");").append(lineSeparator);
                if("session".equals(scope)) {
					recordFileAndLineNr(beanCode);
					beanCode.append("\t\t\t\t__session.putValue(\"").append(javaStringEncode(name)).append("\", ")
							.append(varName).append(");").append(lineSeparator);
 				}
				beanCode.append("\t\t\t} catch(java.lang.ClassNotFoundException cnfexc) {").append(lineSeparator);

				beanCode.append("\t\t\t\t__beanError(response, \"Could not create bean ").append(javaStringEncode(name))
						.append(" of type ").append(javaStringEncode(type)).append(" (class not found)\");").append(lineSeparator);
				beanCode.append("\t\t\t\treturn;").append(lineSeparator);
				beanCode.append("\t\t\t}").append(lineSeparator);
			} else {
				recordFileAndLineNr(beanCode);
				beanCode.append("\t\t\t__beanError(response, \"Bean ").append(javaStringEncode(name))
						.append(" does not exist or is not of type ").append(javaStringEncode(type)).append("\");").append(lineSeparator);
				beanCode.append("\t\t\treturn;");
			}
			beanCode.append("\t\t}").append(lineSeparator);
			if(beanDefaultProperties.size() > 0 || "yes".equalsIgnoreCase(introspect)) {
				beanCode.append("\t\ttry {").append(lineSeparator);
				recordFileAndLineNr(beanCode);
				beanCode.append("\t\t\t__propertyDescriptors = java.beans.Introspector.getBeanInfo(")
						.append(varName).append(".getClass()).getPropertyDescriptors();").append(lineSeparator);
				// set bean default properties
				e = beanDefaultProperties.keys();
				while(e.hasMoreElements()) {
					k = e.nextElement();
					v = beanDefaultProperties.get(k);
					recordFileAndLineNr(beanCode);
					beanCode.append("\t\t\tif(!__beanSetProperty(").append(varName)
							.append(", __propertyDescriptors, \"").append(javaStringEncode(k))
							.append("\", \"").append(javaStringEncode(v)).append("\")) {").append(lineSeparator);
					beanCode.append("\t\t\t\t__beanError(response, \"Bean ").append(javaStringEncode(name))
							.append(" of type").append(javaStringEncode(type)).append(" has no property named ")
							.append(javaStringEncode(k)).append("\");").append(lineSeparator);
					beanCode.append("\t\t\t\treturn;").append(lineSeparator);
					beanCode.append("\t\t\t}").append(lineSeparator);
				}
				// do bean introspection
				if("yes".equalsIgnoreCase(introspect)) {
					recordFileAndLineNr(beanCode);
					beanCode.append("\t\t\t__beanIntrospect(").append(varName)
							.append(", __propertyDescriptors, request);").append(lineSeparator);
				}
				beanCode.append("\t\t} catch(java.beans.IntrospectionException introexc) {").append(lineSeparator);
				beanCode.append("\t\t\t__beanError(response, \"Introspection failed for bean ")
						.append(javaStringEncode(name)).append(" of type ").append(javaStringEncode(type))
						.append("\");").append(lineSeparator);
				beanCode.append("\t\t}").append(lineSeparator);
			}
			beanCode.append(lineSeparator);
		} finally {
			lineNr = endLineNr;
		}
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2009-11-18下午03:01:25
	 * @return 母鸡
	 * @throws StringIndexOutOfBoundsException 解析发生异常
	 */
	protected String[] parseKeyAndValue() throws StringIndexOutOfBoundsException {
		char		c;
		int			pos;
		String[]	keyAndValue = new String[2];
		// gather key
		pos = srcPos;
		while(true) {
			c = src.charAt(srcPos);
			if(c=='=' || Character.isWhitespace(c)) {
				break;
			}
			srcPos++;
		}
		keyAndValue[0] = src.substring(pos, srcPos);
		skipWhitespace();

		// quick work around page processing
		if ("page".equals(keyAndValue[0]) || "include".equals(keyAndValue[0])) {
			return parseKeyAndValue();
		}
		
		// gather optional value
		if(src.charAt(srcPos)=='=') {
			srcPos++;
			skipWhitespace();

			c = src.charAt(srcPos);
			if(c=='\'' || c=='\"') {
				pos = src.indexOf(c, srcPos+1);
				keyAndValue[1] = src.substring(srcPos+1, pos);
				setSrcPos(pos+1);
			} else {
				pos = srcPos;
				while(true) {
					c = src.charAt(srcPos);
					if(c=='%' || c=='>' || Character.isWhitespace(c)) {
						break;
					}
					srcPos++;
				}
				keyAndValue[1] = src.substring(pos, srcPos);
			}

			skipWhitespace();
		} else {
			keyAndValue[1] = keyAndValue[0];
		}

		return keyAndValue;
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2009-11-18下午03:01:48
	 * @param newState 母鸡
	 */
	protected void changeParseState(int newState) {
		if(newState==parseState) {
            return;
        }

		switch(parseState) {
			case PARSE_HTML:
				scriptletsCode.append("\");").append(lineSeparator);
				break;
			case PARSE_EXPRESSION:
				scriptletsCode.append("));").append(lineSeparator);
				break;
			case PARSE_DECLARATION:
				declarationsCode.append(lineSeparator);
				break;
			case PARSE_SCRIPTLET:
				scriptletsCode.append(lineSeparator);
				break;
		}
		parseState = newState;
		switch(parseState) {
			case PARSE_HTML:
				recordFileAndLineNr(scriptletsCode);
				scriptletsCode.append("\t\t\tout.print(\"");
				break;
			case PARSE_EXPRESSION:
				recordFileAndLineNr(scriptletsCode);
				scriptletsCode.append("\t\t\tout.print(__valueOf(");
				break;
			case PARSE_DECLARATION:
				recordFileAndLineNr(declarationsCode);
				break;
			case PARSE_SCRIPTLET:
				recordFileAndLineNr(scriptletsCode);
				break;
		}
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2009-11-18下午03:02:08
	 * @param code 母鸡
	 */
	protected void recordFileAndLineNr(StringBuffer code) {
		//do nice encoding of backslashes in filename
		code.append("//line " + jspFile.toString().replace('\\', '/') + ":" + lineNr).append(lineSeparator);
	}

	/**
	 * 跳过空格回车
	 * @author 刘虻
	 * 2009-11-18下午03:02:28
	 */
	protected void skipWhitespace() {
		while(true) {
			char c = src.charAt(srcPos);
			if(!Character.isWhitespace(c)) {
				break;
			} else if(c=='\n') {
				lineNr++;
			}
			srcPos++;
		}
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2009-11-18下午03:03:02
	 * @param newSrcPos 母鸡
	 */
	protected void setSrcPos(int newSrcPos) {
		int from;
		if(newSrcPos < 0 || newSrcPos >= src.length()) {
			throw new StringIndexOutOfBoundsException(Integer.toString(newSrcPos));
		}
		from = srcPos-1;
		while(true) {
			from = src.indexOf('\n', from+1);
			if(from==-1 || from >= newSrcPos) {
				break;
			}
			lineNr++;
		}
		srcPos = newSrcPos;
	}

	
	/**
	 * 将内容写入文件
	 * 刘虻
	 * 2011-5-17 上午10:43:44
	 * @param fos 文件输出流
	 * @param needEnc 是否需要编码
	 * @param content 文件内容
	 * @throws IOException 异常
	 */
	protected void out(
			FileOutputStream fos,boolean needEnc,String content) throws IOException {
		if(needEnc) {
			fos.write(content.getBytes(contentEncoding));
		}else {
			fos.write(content.getBytes());
		}
		fos.write('\r');
		fos.write('\n');
	}
	
	
	/**
	 * 生成java文件
	 * @author 刘虻
	 * 2009-11-18下午03:03:24
	 * @throws JSPException 执行发生异常
	 */
	protected void generateJavaFile() throws JSPException {
		FileOutputStream fos;
		Enumeration<Object>		e;
		File			f;
		String			pn, cn;
		Long			l;
		int				i;
		boolean needEnc =
                contentEncoding != null && contentEncoding.length() >= 1;
		try {
			f = new File(javaFile.getParent());
			f.mkdirs();
			fos = new FileOutputStream(javaFile);
			i = className.lastIndexOf('.');
			if(i > 0) {
				pn = className.substring(0, i);
				cn = className.substring(i+1);
			} else {
				pn = null;
				cn = className;
			}
			try {
				// generate header and start of class
				out(fos,needEnc,"/* Automatically generated by GNUJSP. Do not edit. */");
				if(pn != null) {
					out(fos,needEnc,"package " + pn + ";");
				}

				out(fos,needEnc,importDirective.toString());
				out(fos,needEnc,"public final class " + cn +
							" extends " + extendsDirective + implementsDirective);
				out(fos,needEnc,"{");

				// generate declarations
				out(fos,needEnc,declarationsCode.toString());
				// generate specified method
				out(fos,needEnc,"\tpublic void " + methodDirective +
							"(javax.servlet.http.HttpServletRequest request, " +
							"javax.servlet.http.HttpServletResponse response) " +
							"throws javax.servlet.ServletException, java.io.IOException");
				out(fos,needEnc,"\t{");
				if(createSession) {
					out(fos,needEnc,"\t\tjavax.servlet.http.HttpSession __session = request.getSession(true);");
				}
				
				out(fos,needEnc,beanCode.toString());
				out(fos,needEnc,"\t\tresponse.setContentType(\"" + javaStringEncode(content_typeDirective) + "\");");
				out(fos,needEnc,"\t\tjava.io.PrintWriter out = response.getWriter();");
				out(fos,needEnc,"\t\ttry {");
				out(fos,needEnc,scriptletsCode.toString());
				out(fos,needEnc,"\t\t}catch(Exception e){");
				out(fos,needEnc,"\t\t\te.printStackTrace();");
				out(fos,needEnc,"\t\t\tout.println(e);");
				out(fos,needEnc,"\t\t} finally {");
				out(fos,needEnc,"\t\t\tout.flush();");
				out(fos,needEnc,"\t\t\tout.close();");
				out(fos,needEnc,"\t\t}");
				out(fos,needEnc,"\t}");
				fos.write('\r');
				fos.write('\n');

				// generate own version of String.valueOf()
				out(fos,needEnc,"\tprivate static java.lang.String __valueOf(java.lang.Object obj) {");
				out(fos,needEnc,"\t\tif(obj==null) {");
				out(fos,needEnc,"\t\t\treturn \"\";");
				out(fos,needEnc,"\t\t} else {");
				out(fos,needEnc,"\t\t\treturn obj.toString();");
				out(fos,needEnc,"\t\t}");
				out(fos,needEnc,"\t}");
				out(fos,needEnc,"\tprivate static java.lang.String __valueOf(boolean b) { return java.lang.String.valueOf(b); }");
				out(fos,needEnc,"\tprivate static java.lang.String __valueOf(char c)    { return java.lang.String.valueOf(c); }");
				out(fos,needEnc,"\tprivate static java.lang.String __valueOf(int i)     { return java.lang.String.valueOf(i); }");
				out(fos,needEnc,"\tprivate static java.lang.String __valueOf(long l)    { return java.lang.String.valueOf(l); }");
				out(fos,needEnc,"\tprivate static java.lang.String __valueOf(float f)   { return java.lang.String.valueOf(f); }");
				out(fos,needEnc,"\tprivate static java.lang.String __valueOf(double d)  { return java.lang.String.valueOf(d); }");
				fos.write('\r');
				fos.write('\n');

				// generate functions
				out(fos,needEnc,functionCode.toString());
				fos.write('\r');
				fos.write('\n');
				
				// generate bean functions
				out(fos,needEnc,"\tprivate void __beanError(javax.servlet.http.HttpServletResponse response, java.lang.String msg) throws java.io.IOException {");
				out(fos,needEnc,"\t\tresponse.setStatus(javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR, \"JSP run-time error\");");
				out(fos,needEnc,"\t\tresponse.setContentType(\"text/html\");");
				out(fos,needEnc,"\t\tjava.io.PrintWriter errOut = response.getWriter();");
				out(fos,needEnc,"\t\terrOut.println(\"<HTML><HEAD><TITLE>\" + javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR + \" JSP run-time error</TITLE></HEAD><BODY>\" +");
				out(fos,needEnc,"\t\t\t\"<H2>\" + javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR + \" JSP run-time error</H2>\" +");
				out(fos,needEnc,"\t\t\t\"The JSP page you requested could not be served because the following error(s) occured:<BR><PRE>\");");
				out(fos,needEnc,"\t\terrOut.println(msg);");
				out(fos,needEnc,"\t\terrOut.println(\"</PRE></BODY></HTML>\");");
				out(fos,needEnc,"\t\terrOut.close();");
				out(fos,needEnc,"\t}");
				fos.write('\r');
				fos.write('\n');

				out(fos,needEnc,"\tprivate boolean __beanSetProperty(java.lang.Object bean, java.beans.PropertyDescriptor[] pds, java.lang.String key, java.lang.String value) {");
				out(fos,needEnc,"\t\tjava.lang.reflect.Method meth;");
				out(fos,needEnc,"\t\tfor(int i = 0; i < pds.length; i++) {");
				out(fos,needEnc,"\t\t\tif(pds[i].getName().equals(key) && !pds[i].isHidden()) {");
				out(fos,needEnc,"\t\t\t\tmeth = pds[i].getWriteMethod();");
				out(fos,needEnc,"\t\t\t\tif(meth != null) {");
				out(fos,needEnc,"\t\t\t\t\ttry {");
				out(fos,needEnc,"\t\t\t\t\t\tmeth.invoke(bean, new Object[]{value});");
				out(fos,needEnc,"\t\t\t\t\t\treturn true;");
				out(fos,needEnc,"\t\t\t\t\t} catch(java.lang.IllegalAccessException iaccexc) {");
				out(fos,needEnc,"\t\t\t\t\t\treturn false;");
				out(fos,needEnc,"\t\t\t\t\t} catch(java.lang.IllegalArgumentException iargexc) {");
				out(fos,needEnc,"\t\t\t\t\t\treturn false;");
				out(fos,needEnc,"\t\t\t\t\t} catch(java.lang.reflect.InvocationTargetException itexc) {");
				out(fos,needEnc,"\t\t\t\t\t\treturn false;");
				out(fos,needEnc,"\t\t\t\t\t}");
				out(fos,needEnc,"\t\t\t\t}");
				out(fos,needEnc,"\t\t\t}");
				out(fos,needEnc,"\t\t}");
				out(fos,needEnc,"\t\treturn false;");
				out(fos,needEnc,"\t}");
				fos.write('\r');
				fos.write('\n');

				out(fos,needEnc,"\tprivate void __beanIntrospect(java.lang.Object bean, java.beans.PropertyDescriptor[] pds, javax.servlet.http.HttpServletRequest request) {");
				out(fos,needEnc,"\t\tjava.lang.reflect.Method meth;");
				out(fos,needEnc,"\t\tjava.lang.String value;");
				out(fos,needEnc,"\t\tfor(int i = 0; i < pds.length; i++) {");
				out(fos,needEnc,"\t\t\tif(!pds[i].isHidden()) {");
				out(fos,needEnc,"\t\t\t\tvalue = request.getParameter(pds[i].getName());");
				out(fos,needEnc,"\t\t\t\tif(value != null) {");
				out(fos,needEnc,"\t\t\t\t\tmeth = pds[i].getWriteMethod();");
				out(fos,needEnc,"\t\t\t\t\tif(meth != null) {");
				out(fos,needEnc,"\t\t\t\t\t\ttry {");
				out(fos,needEnc,"\t\t\t\t\t\t\tmeth.invoke(bean, new Object[]{value});");
				out(fos,needEnc,"\t\t\t\t\t\t} catch(java.lang.IllegalAccessException iaccexc) {");
				out(fos,needEnc,"\t\t\t\t\t\t\t//");
				out(fos,needEnc,"\t\t\t\t\t\t} catch(java.lang.IllegalArgumentException iargexc) {");
				out(fos,needEnc,"\t\t\t\t\t\t\t//");
				out(fos,needEnc,"\t\t\t\t\t\t} catch(java.lang.reflect.InvocationTargetException itexc) {");
				out(fos,needEnc,"\t\t\t\t\t\t\t//");
				out(fos,needEnc,"\t\t\t\t\t\t}");
				out(fos,needEnc,"\t\t\t\t\t}");
				out(fos,needEnc,"\t\t\t\t}");
				out(fos,needEnc,"\t\t\t}");
				out(fos,needEnc,"\t\t}");
				out(fos,needEnc,"\t}");
				fos.write('\r');
				fos.write('\n');

				// generate dependency check code
				out(fos,needEnc,"\tpublic static final int __compilerVersionNr = " + COMPILER_VERSION_NR + ";");
				fos.write('\r');
				fos.write('\n');

				out(fos,needEnc,"\tprivate static java.lang.Object[] __dependencies = new java.lang.Object[]{");
				e = dependencies.elements();
				while(true) {
					f = (File) e.nextElement();
					l = (Long) e.nextElement();
					out(fos,needEnc,"\t\tnew java.io.File(\"" + javaStringEncode(f.toString()) + "\"),");
					fos.write(("\t\tnew java.lang.Long(" + l + "L)").getBytes());
					if(e.hasMoreElements()) {
						out(fos,needEnc,",");
					} else {
						fos.write('\r');
						fos.write('\n');
						break;
					}
				}
				out(fos,needEnc,"\t};");
				fos.write('\r');
				fos.write('\n');

				out(fos,needEnc,"\tpublic static boolean __checkDependencies() {");
				out(fos,needEnc,"\t\tfor(int i = 0; i < __dependencies.length; i += 2) {");
				out(fos,needEnc,"\t\t\tif(!((java.io.File) __dependencies[i]).exists() ||");
				out(fos,needEnc,"\t\t\t\t\t((java.io.File) __dependencies[i]).lastModified() > ((java.lang.Long) __dependencies[i+1]).longValue()) {");
				out(fos,needEnc,"\t\t\t\treturn true;");
				out(fos,needEnc,"\t\t\t}");
				out(fos,needEnc,"\t\t}");
				out(fos,needEnc,"\t\treturn false;");
				out(fos,needEnc,"\t}");

				// generate end of class
				out(fos,needEnc,"}");
			} finally {
				fos.close();
			}
		} catch(IOException ioexc) {
			throw new JSPException("Could not write java file " + javaFile + ": " + ioexc.getMessage());
		}
	}

	/**
	 * url转文件路径
	 * @author 刘虻
	 * 2009-11-18下午03:04:06
	 * @param url url路径
	 * @return 文件路径
	 * @deprecated
	 */
    protected final String toFile(URL url) {
		if (url.getProtocol().indexOf("file") < 0) {
            return null;
        }
		String result = url.getPath();
		if (result.charAt(0)=='/' && File.separatorChar=='\\') {
			result = result.substring(1);
		}
		return URLDecoder.decode(result);
	}
	
	/**
	 * 处理获取类路径
	 * @author 刘虻
	 * 2009-11-18下午03:04:47
	 * @param cl 类加载器
	 * @return 类路径
	 */
	protected String calculateClassPath(ClassLoader cl) {
		// scan cl chain to find
		StringBuffer classPath = new StringBuffer();
		boolean servletFound = false;
		while (cl != null) {
			if (cl instanceof URLClassLoader) {
				boolean addClasses = false;
				servletFound = ((URLClassLoader) cl).findResource("javax/servlet/http/HttpServlet.class") != null;
				addClasses |= servletFound;
				if (addClasses) {
					URL[] urls = ((URLClassLoader) cl).getURLs();
					for (int i = 0; i < urls.length; i++) {
						//类路径
						String classFile = toFile(urls[i]);
						if (classFile==null) {
							continue;
						}
						if (classPath.length() > 0) {
							classPath.append(File.pathSeparatorChar).append(classFile);
						}else {
							classPath.append(classFile);
						}
					}
				}
				if (servletFound) {
					return classPath.toString();
				}
			}
			cl = cl.getParent();
		}
		return System.getProperty("java.class.path");
	}
	
	
	/**
	 * 编译java类
	 * @author 刘虻
	 * 2009-11-18下午03:05:09
	 * @throws JSPException 执行发生异常
	 */
	protected void compileJavaFile() throws JSPException {
		String classPath = null; //类路径
		String objPath = null; //目标文件夹
		String srcPath = null; //源文件路径
		String t = null; //临时段
		for(int i = 1; i < jspServlet.compiler.length; i++) {
			String s = jspServlet.compiler[i];
			StringBuffer buf = new StringBuffer(s.length() + 16);
			int k = s.indexOf('%');
			int l = -1;
			while(k != -1) {
				buf.append(s, l+1, k);
				l = s.indexOf('%', k+1);
				if(l==-1) {
					l = k-1;
					break;
				} else {
					t = s.substring(k+1, l);
					if(t.length()==0) {
						t = "%";
					} else if("classpath".equalsIgnoreCase(t)) {
						classPath = calculateClassPath(ClassLoader.getSystemClassLoader());
					} else if("repository".equalsIgnoreCase(t)) {
						objPath = jspServlet.repository.toString();
					} else if("source".equalsIgnoreCase(t)) {
						srcPath = javaFile.toString();
					} else {
						t = jspServlet.getServletConfig().getInitParameter(t);
					}
					if(t != null) {
						buf.append(t);
					}
					k = s.indexOf('%', l+1);
				}
			}
		}
		//JSP Class 编码
		String enc = pageEncoding;
		if(enc==null) {
			enc = contentEncoding;
		}
		try {
			(new JavacTool()).compileJavaFile(srcPath,objPath,enc,classPath);
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
	
	
	/**
	 * HMTML编码
	 * @author 刘虻
	 * 2009-11-18下午03:05:23
	 * @param val 内容
	 * @return 编码
	 */
	protected static String htmlEncode(String val) {
		StringBuffer	buf = new StringBuffer(val.length() + 8);
		char			c;

		for(int i=0; i<val.length(); i++) {
			c = val.charAt(i);
			switch(c) {
				case '<':
					buf.append("&lt;");
					break;
				case '>':
					buf.append("&gt;");
					break;
				case '&':
					buf.append("&amp;");
					break;
				default:
					buf.append(c);
					break;
			}
		}
		return buf.toString();
	}

	/**
	 * 母鸡
	 * @author 刘虻
	 * 2009-11-18下午03:06:02
	 */
	protected static class MapEntry {
		int			javaLineNr;
		String		jspFile;
		int			jspLineNr;

		MapEntry(int javaLineNr, String jspFile, int jspLineNr) {
			this.javaLineNr = javaLineNr;
			this.jspFile = jspFile;
			this.jspLineNr = jspLineNr;
		}
	}

	/**
	 * 整理错误信息
	 * @author 刘虻
	 * 2009-11-18下午03:06:51
	 * @param errors 错误信息
	 * @return 整理后的错误信息
	 */
	protected String transcribeErrors(String errors) {
		LineNumberReader	in;
		BufferedReader		in2;
		Vector<Object>				map;
		Enumeration<Object>			e;
		MapEntry			entry;
		StringBuffer		errBuf;
		String				s, jspFile;
		int					i, j, k, l, javaLineNr, jspLineNr;

		try {
			/* Build mapping from java line numbers to jsp file/line# combinations.
			 * We could have done this will writing the java file, but using
			 * LineNumberReader is easier, and it would take extra time when
			 * no errors occur.
			 */
			in = new LineNumberReader(new FileReader(javaFile));
			in.setLineNumber(1);
			map = new Vector<Object>();
			try {
				while((s = in.readLine()) != null) {
					if(s.startsWith("//line ")) {
						i = s.indexOf(':');
						if(i >= 0) {
							try {
								map.addElement(new MapEntry(in.getLineNumber(),
									s.substring(7, i), Integer.parseInt(s.substring(i+1))));
							} catch(NumberFormatException nfexc) { }
						}
					}
				}
			} finally {
				in.close();
			}

			/* Now we read every line of the error messages and translate any
			 * file references there.
			 */
			in2 = new BufferedReader(new StringReader(errors));
			errBuf = new StringBuffer();
			try {
				while((s = in2.readLine()) != null) {
					i = s.indexOf(javaFile.getPath());
					if(i != -1) {
						j = i + javaFile.getPath().length();
						if(j < s.length()-1 && s.charAt(j)==':' && Character.isDigit(s.charAt(j+1))) {
							j++;
							k = j;
							while(k < s.length() && Character.isDigit(s.charAt(k))) {
								k++;
							}
							l = k;
							while(l+1 < s.length() && s.charAt(l)==':' && Character.isDigit(s.charAt(l+1))) {
								l += 2;
								while(l < s.length() && Character.isDigit(s.charAt(l))) {
									l++;
								}
							}

							try {
								javaLineNr = Integer.parseInt(s.substring(j, k));
								jspFile = null;
								jspLineNr = 0;
								for(e = map.elements(); e.hasMoreElements(); ) {
									entry = (MapEntry) e.nextElement();
									if(entry.javaLineNr > javaLineNr) {
										break;
									}
									jspFile = entry.jspFile;
									jspLineNr = entry.jspLineNr + (javaLineNr - entry.javaLineNr);
								}
								// valid translation found: use it
								if(jspFile != null) {
									errBuf.append(s, 0, i);
									errBuf.append("<B>").append(jspFile).append(':').append(jspLineNr).append("</B>");
									errBuf.append("<!-- ").append(s, i, l).append(" -->");
									errBuf.append(s.substring(l)).append(lineSeparator);
									continue;
								}
							} catch(NumberFormatException nfexc2) { }
						}
					}
					errBuf.append(s).append(lineSeparator);
				}
				return errBuf.toString();
			} finally {
				in2.close();
			}
		} catch(IOException ioexc) {
			return errors;
		}
	}

	/**
	 * 生成Java类
	 * @author 刘虻
	 * 2009-11-18下午02:48:21
	 * @param val 源内容
	 * @return java内容
	 */
	protected static String javaStringEncode(String val) {
		//构建返回值
		StringBuffer res = new StringBuffer(val.length());
		for(int i=0; i<val.length(); i++) {
			char oneCHar = val.charAt(i); //获取字符元素
			switch(oneCHar) {
			case '\n':
				res.append("\\n");
				break;
			case '\r':
				res.append("\\r");
				break;
			case '\'':
				res.append("\\\'");
				break;
			case '\"':
				res.append("\\\"");
				break;
			case '\\':
				res.append("\\\\");
				break;
			default:
				String sub; //段
				if(oneCHar>0xFF) {
					sub = "00" + Integer.toHexString(oneCHar);
					res.append("\\u").append(sub.substring(sub.length() - 4));
				} else if(oneCHar<' ' || oneCHar>=0x7F) {
					sub = "00" + Integer.toOctalString(oneCHar);
					res.append('\\').append(sub.substring(sub.length() - 3));
				} else {
					res.append(oneCHar);
				}
				break;
			}
		}
		return res.toString();
	}

	
	/**
	 * 通过JSP文件对象获取路径
	 * @author 刘虻
	 * 2009-11-18下午03:07:08
	 * @param jspFile jsp文件对象
	 * @return 路径
	 * @throws JSPException 执行发生异常
	 */
	public static String getClassNameForJspFile(File jspFile) throws JSPException {
		StringTokenizer		toker;
		StringBuffer		buf;
		String				s = jspFile.toString();
		char				c;
		int					i;

		toker = new StringTokenizer(s, String.valueOf(File.separatorChar));
		buf = new StringBuffer(s.length() + 32);
		buf.append("_jsp");
		while(toker.hasMoreTokens()) {
			s = toker.nextToken();
			buf.append("._");
			for(i = 0; i < s.length(); i++) {
				c = s.charAt(i);
				if(Character.isJavaIdentifierPart(c)) {
					buf.append(c);
				} else {
					buf.append('_').append(Integer.toHexString(c));
				}
			}
		}

		return buf.toString();
	}

	/**
	 * 通过类名获取对应的类文件
	 * @author 刘虻
	 * 2009-11-18下午03:07:52
	 * @param repository 类根路径
	 * @param className 类名
	 * @param suffix 扩展名
	 * @return 类文件
	 */
	public static File getFileForClass(File repository, String className, String suffix) {
		return new File(repository, className.replace('.', File.separatorChar) + suffix);
	}
}
